package org.spring.boot.fusion.auth.server.handler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.spring.boot.fusion.auth.server.service.FusionLoginCallbackService;
import org.spring.boot.fusion.common.constant.ConstantAttribute;
import org.spring.boot.fusion.common.exception.ServiceErrorStatus;
import org.spring.boot.fusion.common.exception.ServiceRunTimeException;
import org.spring.boot.fusion.common.response.ResponseData;
import org.spring.boot.fusion.common.tools.JsonTool;
import org.spring.boot.fusion.security.properties.FusionTokenProperties;
import org.spring.boot.fusion.security.user.FusionUserData;
import org.spring.boot.fusion.security.user.FusionUserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

@Component
@SuppressWarnings("deprecation")
public class FusionLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

	@Autowired
	private FusionTokenProperties tokenConfigProperties;
	@Autowired
	private ClientDetailsService clientDetailsService;
	@Autowired
	private FusionLoginCallbackService loginCallbackService;
	@Autowired
	private AuthorizationServerTokenServices authorizationServerTokenServices;

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		response.setHeader("Access-Control-Allow-Origin", "*");		
		String headerUsername = tokenConfigProperties.getUsername();
		String headerPassword = tokenConfigProperties.getPassword();
		byte[] encode = Base64.encode(String.valueOf(headerUsername+":"+headerPassword).getBytes());
		String header = "Basic "+new String(encode);
		if (header == null || !header.startsWith("Basic ")) {
			response.getWriter().write(JsonTool.ObjectToJson(authentication));
			return;
		}
		String[] tokens = extractAndDecodeHeader(header, request);
		assert tokens.length == 2;
		String clientId = tokens[0];
		String clientSecret = tokens[1];
		
		ClientDetails loadClientByClientId = clientDetailsService.loadClientByClientId(clientId);
		if(loadClientByClientId==null){
			response.getWriter().write(JsonTool.ObjectToJson(authentication));
			return;
		}
		if(!clientSecret.equals(loadClientByClientId.getClientSecret())){
			response.getWriter().write(JsonTool.ObjectToJson(authentication));
			return;
		}
		
		@SuppressWarnings({ "unchecked", "rawtypes" })
		TokenRequest tokenRequest = new TokenRequest(new HashMap(1), clientId, loadClientByClientId.getScope(), "custom");
		OAuth2Request createOAuth2Request = tokenRequest.createOAuth2Request(loadClientByClientId);
		OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(createOAuth2Request, authentication);
		OAuth2AccessToken createAccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
		FusionUserDetails userData = FusionUserData.getUserData();
		Map<String, Object> hashMap = userData.getResponseMap();
		hashMap.put("access_token", createAccessToken.getValue());
		hashMap.put("token_type", createAccessToken.getTokenType());
		hashMap.put("refresh_token", createAccessToken.getRefreshToken().getValue());
		hashMap.put("expires_in", createAccessToken.getExpiresIn());
		String userId = userData.getId();
		if(userId!=null && !userId.equalsIgnoreCase("null") && userId.length()>0) {
			hashMap.put("id",userId);
		}
		String username = userData.getUsername();
		if(username!=null && !username.equalsIgnoreCase("null") && username.length()>0) {
			hashMap.put("username",username);
		}
		response.setStatus(HttpStatus.OK.value());
		response.setContentType(ConstantAttribute.JSON_TYPE_UTF8);
		response.getWriter().write(JsonTool.ObjectToJson(ResponseData.SUCCESS(loginCallbackService.loginCallback(hashMap))));
	}
	private String[] extractAndDecodeHeader(String header, HttpServletRequest request)
			throws IOException {

		byte[] base64Token = header.substring(6).getBytes("UTF-8");
		byte[] decoded;
		try {
			decoded = Base64.decode(base64Token);
		}
		catch (IllegalArgumentException e) {
			throw new ServiceRunTimeException(ServiceErrorStatus.CREATE_TOKEN_ERROR);
		}

		String token = new String(decoded,"UTF-8");

		int delim = token.indexOf(":");

		if (delim == -1) {
			throw new ServiceRunTimeException(ServiceErrorStatus.CREATE_TOKEN_ERROR);
		}
		return new String[] { token.substring(0, delim), token.substring(delim + 1) };
	}
}
